AWS Step Functionsで変数とJSONataを活用し、Passステートで組み込み関数を使用したりChoiceで分岐させてみた

AWS Step Functionsで変数とJSONataを活用し、Passステートで組み込み関数を使用したりChoiceで分岐させてみた

Clock Icon2025.01.15

はじめに

AWS Step Functionsの変数とJSONataを活用し、Passステートで処理を行ったり、Choiceで分岐させてみました。

以前、AWS Step Functionsで変数とJSONataが利用可能になるアップデートがありました。

AWS Step Functionsのステートマシン内でJSONataを利用することで、PassステートでJSONPathでは実現できなかった複雑な処理を行ったり、渡された値を変数として容易に活用してステートマシン内で処理を実行することが可能です。

また、JSONPath形式に加えてJSONataも利用できるようになったため、JSONataを活用した変数の記述方法について解説します。

処理例

今回の例として、ステートマシンで処理している内容は以下の通りです。参考にした元記事は以下です。

https://dev.classmethod.jp/articles/amazon-connect-bedrock-kds-stepfunctions-email/

内容は、Amazon Connectで自動ヒアリングした内容をAmazon Bedrockで要約し、メール通知する方法を、Amazon Kinesis Data Streams(以下、KDS)とAWS Step Functionsを用いて実装したものです。

処理の内容は以下の通りです。

  1. Kinesis Data Streams(以下、KDS)からEventBridge Pipesを経由してステートマシンをトリガーする。
    • ヒアリング内容であるコンタクト属性(recording)、コンタクトID、発信元電話番号などが渡される。
  2. コンタクト属性(recording)がnullではないか確認
  3. BedrockのClaudeを利用して、文字起こし内容を整形する
  4. 整形した内容をSNSトピックを通じてメール送信する

以下に構成図を示します。

cm-hirai-screenshot 2024-12-23 8.51.07

ワークフローとしては、以下の図の通りです。各ステートごとに章立てで解説します。

cm-hirai-screenshot 2024-12-23 14.16.34

各ステートにおいて、状態の入力(以降、ステートの入力)と状態の出力(以降、ステートの出力)は、以下の実行ログ(State View)から確認できます。

cm-hirai-screenshot 2024-12-23 15.12.38

Pass state(Base64Decode)ステート

まずは、Pass state(Base64Decode)ステートについて解説します。

cm-hirai-screenshot 2024-12-23 14.16.34

本ステートでは変数のみを設定し、[設定]と[出力]については特に記載しません。

EventBridge Pipes内でKDSからステートマシンに渡される内容は、以下のとおりです。

{
  "eventSource": "aws:kinesis",
  "eventVersion": "1.0",
  "eventID": "shardId-000000000000:xxxxxxxxx",
  "eventName": "aws:kinesis:record",
  "invokeIdentityArn": "arn:aws:iam::xxxxxxxxxxxx:role/service-role/Amazon_EventBridge_Pipe_cm-hirai-voicemail-to-email-sf_cbcfa279",
  "awsRegion": "ap-northeast-1",
  "eventSourceARN": "arn:aws:kinesis:ap-northeast-1:xxxxxxxxxxxx:stream/cm-hirai",
  "kinesisSchemaVersion": "1.0",
  "partitionKey": "19a1c22c-399d-4c6b-b766-9832832c9005",
  "sequenceNumber": "xxxxxxxxx",
  "data": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "approximateArrivalTimestamp": 1733793205.123
}

上記のうちdataはBase64でエンコードされているため、Pass state(Base64Decode)ステートでデコードし、次のステートでJSONデータをパースして以下のような値を取得できるようにします。

{
  "data": {
    "AWSAccountId": "012345678901",
    "AWSContactTraceRecordFormatVersion": "2017-03-10",
    "Agent": null,
    "AgentConnectionAttempts": 0,
    "AnsweringMachineDetectionStatus": null,
    "Attributes": {
      "recording": "お問い合わせ内容〇〇"
    },
    "Campaign": {
      "CampaignId": null
    },
    "Channel": "VOICE",
    "ConnectedToSystemTimestamp": "2024-12-10T01:11:43Z",
    "ContactDetails": {},
    "ContactId": "19a1c22c-399d-4c6b-b766-9832832c9005",
    "CustomerEndpoint": {
      "Address": "+81xxxxxxxx",
      "Type": "TELEPHONE_NUMBER"
    },
    "CustomerVoiceActivity": null,
    "DisconnectReason": "CONTACT_FLOW_DISCONNECT",
    "DisconnectTimestamp": "2024-12-10T01:12:22Z",
    "InitialContactId": null,
    "InitiationMethod": "INBOUND",
    "InitiationTimestamp": "2024-12-10T01:11:43Z",
    "InstanceARN": "arn:aws:connect:ap-northeast-1:012345678901:instance/3ff2093d-af96-43fd-b038-3c07cdd7609c",
    "LastUpdateTimestamp": "2024-12-10T01:13:24Z",
    "MediaStreams": [
      {
        "Type": "AUDIO"
      }
    ],
    "NextContactId": null,
    "PreviousContactId": null,
    "Queue": null,
    "Recording": null,
    "Recordings": null,
    "References": [],
    "ScheduledTimestamp": null,
    "SegmentAttributes": {
      "connect:Subtype": {
        "ValueInteger": null,
        "ValueMap": null,
        "ValueString": "connect:Telephony"
      }
    },
    "SystemEndpoint": {
      "Address": "+81xxxxxxxx",
      "Type": "TELEPHONE_NUMBER"
    },
    "Tags": {
      "aws:connect:instanceId": "3ff2093d-af96-43fd-b038-3c07cdd7609c",
      "aws:connect:systemEndpoint": "+81xxxxxxxx"
    },
    "TaskTemplateInfo": null,
    "TransferCompletedTimestamp": null,
    "TransferredToEndpoint": null,
    "VoiceIdResult": null
  }
}

変数

このステートで渡される値にはdataが含まれています。

渡される値の一部
{
  "data": "xxxxxxxIjIwMjQtMTItMTBUMDE6MTM6MjRaIiwiTWVkaWFTdHJlYW1zIjpbeyJUeXBlIjoiQVVESU8ifV0sIk5leHRDb250YWN0SWQiOm51bGwsIlByZXZpb3VzQ29udGFjdElkIjpudWxsLCJRdWV1ZSI6bnVsbCwiUmVjb3JkaW5nIjpudWxsLCJSZWNvcmRpbmdzIjpudWxsLCJSZWZlcmVuY2VzIjpbXSwiU2NoZWR1bGVkVGltZXN0YW1wIjpudWxsLCJTZWdtZW50QXR0cmlidXRlcyI6eyJjb25uZWN0OlN1YnR5cGUiOnsiVmFsdWVJbnRlZ2VyIjpudWxsLCJWYWx1ZU1hcCI6bnVsbCwiVmFsdWVTdHJpbmciOiJjb25uZWN0OlRlbGVwaG9ueSJ9fSwiU3lzdGVtRW5kcG9pbnQiOnsiQWRkcmVzcyI6Iis4MTUwMzA5MDI1MjkiLCJUeXBlIjoiVEVMRVBIT05FX05VTUJFUiJ9LCJUYWdzIjp7ImF3czpjb25uZWN0Omluc3RhbmNlSWQiOiIzZmYyMDkzZC1hZjk2LTQzZmQtYjAzOC0zYzA3Y2RkNzYwOWMiLCJhd3M6Y29ubmVjdDpzeXN0ZW1FbmRwb2ludCI6Iis4MTUwMzA5MDI1MjkifSwiVGFza1RlbXBsYXRlSW5mbyI6bnVsbCwiVHJhbnNmZXJDb21wbGV0ZWRUaW1lc3RhbXAiOm51bGwsIlRyYW5zZmVycmVkVG9FbmRwb2ludCI6bnVsbCwiVm9pY2VJZFJlc3VsdCI6bnVsbH0="}

dataはBase64でエンコードされているため、本ステートでデコードし、次のステートでJSONデータをパースします。

そのため、本ステートでは以下のように変数を設定します。dataをBase64デコードした値を変数名decodedDataとして定義しました。

変数
{
  "decodedData": "{% $base64decode($states.input.data) %}"
}

cm-hirai-screenshot 2024-12-23 14.16.54

変数内で「b」を入力すると、「$base64decode()」が候補として表示されます。

cm-hirai-screenshot 2024-12-10 10.45.02

JSONataのドキュメントから、利用可能な関数を確認できます。base64decode関数もその中に含まれています。

https://docs.jsonata.org/string-functions#base64decode

cm-hirai-screenshot 2024-12-10 10.53.32
JSONataのドキュメント

ちなみに、AWS サービスの連携ステート(Task state)を利用する場合、リクエスト結果を$states.resultとして変数にすることはできますが、$states.resultはAPI が成功した場合の結果を指します。

Pass stateは、APIの結果ではないため、$states.resultは利用できません。
Pass stateで処理した内容は、{% $base64decode($states.input.data) %}と記載することで、変数にできます。

vars-jsonata
引用元:https://docs.aws.amazon.com/step-functions/latest/dg/transforming-data.html#jsonata-functions-provided-by-sfn

テスト

ステートでは、[テスト状態]からテストを実行できます。

[ステートの入力]を設定し、[テストを開始]からテストを実行すると、[アドバンスト]で変数の結果を確認できます。[ステートの出力]を設定していない場合、[ステートの入力]がそのまま[ステートの出力]として使用されます。

[変数]はBase64エンコードした内容が確認できます。

cm-hirai-screenshot 2024-12-23 13.39.06

実行ログ(State View)からも確認できますが、Base64エンコードされた内容は確認できません。これは、出力が設定されていないためです。

cm-hirai-screenshot 2024-12-23 13.23.31

ステートで[出力]を設定していない場合、実行ログのグラフビューの右から[変数]が確認できます。

cm-hirai-screenshot 2024-12-23 13.29.04

"{"AWSAccountId":"xxxxxxxxxxxx","AWSContactTraceRecordFormatVersion":"2017-03-10","Agent":null,"AgentConnectionAttempts":0,"AnsweringMachineDetectionStatus":null,"Attributes":{"recording":"加湿 器 が 壊れ た の で 連絡 し まし た シライ ユウジ です 十 五 時 に また 連絡 下さい"},"Campaign":{"CampaignId":null},"Channel":"VOICE","ConnectedToSystemTimestamp":"2024-12-10T01:11:43Z","ContactDetails":{},"ContactId":"19a1c22c-399d-4c6b-b766-9832832c9005","CustomerEndpoint":{"Address":"+81xxxxxxxx","Type":"TELEPHONE_NUMBER"},"CustomerVoiceActivity":null,"DisconnectReason":"CONTACT_FLOW_DISCONNECT","DisconnectTimestamp":"2024-12-10T01:12:22Z","InitialContactId":null,"InitiationMethod":"INBOUND","InitiationTimestamp":"2024-12-10T01:11:43Z","InstanceARN":"arn:aws:connect:ap-northeast-1:xxxxxxxxxxxx:instance/3ff2093d-af96-43fd-b038-3c07cdd7609c","LastUpdateTimestamp":"2024-12-10T01:13:24Z","MediaStreams":[{"Type":"AUDIO"}],"NextContactId":null,"PreviousContactId":null,"Queue":null,"Recording":null,"Recordings":null,"References":[],"ScheduledTimestamp":null,"SegmentAttributes":{"connect:Subtype":{"ValueInteger":null,"ValueMap":null,"ValueString":"connect:Telephony"}},"SystemEndpoint":{"Address":"+81xxxxxxxx","Type":"TELEPHONE_NUMBER"},"Tags":{"aws:connect:instanceId":"3ff2093d-af96-43fd-b038-3c07cdd7609c","aws:connect:systemEndpoint":"+81xxxxxxxx"},"TaskTemplateInfo":null,"TransferCompletedTimestamp":null,"TransferredToEndpoint":null,"VoiceIdResult":null}"

Pass state(ParseJSON)ステート

次に、Pass state(ParseJSON)ステートについて解説します。

cm-hirai-screenshot 2024-12-23 14.16.34

本ステートでは、設定と出力については特に記載しません。そのため、コメントもありません。

変数

前のステートでdataはBase64デコードされ(変数名decodedData)、本ステートではJSONデータをパースして、dataから以下のような値を取得します。
文字起こし内容のコンタクト属性(recording)も確認できます。

{
  "data": {
    "AWSAccountId": "012345678901",
    "AWSContactTraceRecordFormatVersion": "2017-03-10",
    "Agent": null,
    "AgentConnectionAttempts": 0,
    "AnsweringMachineDetectionStatus": null,
    "Attributes": {
      "recording": "お問い合わせ内容〇〇"
    },
    "Campaign": {
      "CampaignId": null
    },
    "Channel": "VOICE",
    "ConnectedToSystemTimestamp": "2024-12-10T01:11:43Z",
    "ContactDetails": {},
    "ContactId": "19a1c22c-399d-4c6b-b766-9832832c9005",
    "CustomerEndpoint": {
      "Address": "+81xxxxxxxx",
      "Type": "TELEPHONE_NUMBER"
    },
    "CustomerVoiceActivity": null,
    "DisconnectReason": "CONTACT_FLOW_DISCONNECT",
    "DisconnectTimestamp": "2024-12-10T01:12:22Z",
    "InitialContactId": null,
    "InitiationMethod": "INBOUND",
    "InitiationTimestamp": "2024-12-10T01:11:43Z",
    "InstanceARN": "arn:aws:connect:ap-northeast-1:012345678901:instance/3ff2093d-af96-43fd-b038-3c07cdd7609c",
    "LastUpdateTimestamp": "2024-12-10T01:13:24Z",
    "MediaStreams": [
      {
        "Type": "AUDIO"
      }
    ],
    "NextContactId": null,
    "PreviousContactId": null,
    "Queue": null,
    "Recording": null,
    "Recordings": null,
    "References": [],
    "ScheduledTimestamp": null,
    "SegmentAttributes": {
      "connect:Subtype": {
        "ValueInteger": null,
        "ValueMap": null,
        "ValueString": "connect:Telephony"
      }
    },
    "SystemEndpoint": {
      "Address": "+81xxxxxxxx",
      "Type": "TELEPHONE_NUMBER"
    },
    "Tags": {
      "aws:connect:instanceId": "3ff2093d-af96-43fd-b038-3c07cdd7609c",
      "aws:connect:systemEndpoint": "+81xxxxxxxx"
    },
    "TaskTemplateInfo": null,
    "TransferCompletedTimestamp": null,
    "TransferredToEndpoint": null,
    "VoiceIdResult": null
  }
}

変数の設定は以下の通りです。

dataのJSONデータをパースするため、JSONataのparse関数を利用します。

{
  "data": "{% $parse($decodedData) %}",
  "InitialContactId": "{% $parse($decodedData).ContactId %}",
  "Time": "{% $parse($decodedData).InitiationTimestamp %}",
  "CallerPhoneNumber": "{% $parse($decodedData).SystemEndpoint.Address %}"
}

cm-hirai-screenshot 2024-12-23 14.17.07

  • 変数名とその値は以下の通りです。
    • data:data(JSONデータのパース結果)
    • InitialContactId:contactId(コンタクトID)
    • Time:initiationTimestamp(電話の対応日時)
    • CallerPhoneNumber:aws:connect:systemEndpoint(架電の電話番号)

変数名data以外の3つの変数は、後続のBedrockやSNSステートで利用します。
これらの変数は、Connectの問い合わせレコードをKDSにストリーミングされる際に、必ず存在しますのでこの時点で変数にします。

変数名dataを定義する理由は、次のChoiceステートでコンタクト属性recordingが存在するか確認するためです。
コンタクト属性recordingは、Connectの問い合わせレコードをKDSにストリーミングされる際に存在しない可能性があり、本ステートで変数にする場合、recordingが存在しなかった場合エラーになってしまいます。

本ステートの設定は以上です。

Passステートを組み合わせることも可能

ちなみに、Pass state(Base64Decode)ステートとPass state(ParseJSON)ステートは、一つのPass stateに以下の通り集約させることも可能です。

変数
{
  "data": "{% $parse($base64decode($states.input.data)) %}",
  "InitialContactId": "{% $parse($base64decode($states.input.data)).ContactId %}",
  "Time": "{% $parse($base64decode($states.input.data)).InitiationTimestamp %}",
  "CallerPhoneNumber": "{% $parse($base64decode($states.input.data)).SystemEndpoint.Address %}"
}

dataをbase64デコードして、JSONデータをパースを1つのステートで行います。

変数とJSONataの処理を理解しやすくなるよう、今回は1つの処理ごとにステートを分けました。

Choiceステート

次に、Choiceステートについて解説します。

cm-hirai-screenshot 2024-12-23 14.16.34

Rule

Ruleで設定したConditionは以下の通りです。dataにコンタクト属性recordingが存在するかをチェックします。
先ほど設定した変数名dataを利用します。

Condition
{% $data.Attributes.recording != null %}

recordingが存在する場合、その値を変数として設定します。この変数は後続のステートで利用されます。

割り当てられた変数
{
  "recording": "{% $data.Attributes.recording %}"
}

cm-hirai-screenshot 2024-12-23 14.33.27

Default Rule

コンタクト属性recordingが存在しない場合、出力や変数は特に設定しません。

Pass stateを経由してEndに遷移します。

Choiceのみでも可能

余談ですが、Choiceステートで、Conditionと割り当てられた変数を以下のように設定すると、Pass state(Base64Decode)ステートとPass state(ParseJSON)ステートを省略できます。

Condition
{% $parse($base64decode($states.input.data)).Attributes.recording != null %}
割り当てられた変数
{
  "Type": "Choice",
  "Choices": [
    {
      "Condition": "{% $parse($base64decode($states.input.data)).Attributes.recording != null %}",
      "Next": "Bedrock InvokeModel",
      "Assign": {
        "recording": "{% $parse($base64decode($states.input.data)).Attributes.recording %}",
        "InitialContactId": "{% $parse($base64decode($states.input.data)).ContactId %}",
        "Time": "{% $parse($base64decode($states.input.data)).InitiationTimestamp %}",
        "CallerPhoneNumber": "{% $parse($base64decode($states.input.data)).SystemEndpoint.Address %}"
      }
    }
  ],
  "Default": "Pass"
}

cm-hirai-screenshot 2024-12-23 14.39.45

今回は、ワークフローのわかりやすさを重視するため、3つのステートを利用しました。

Bedrock InvokeModel

次に、BedrockのInvokeModelステートについて解説します。

cm-hirai-screenshot 2024-12-23 14.16.34
BedrockのClaudeモデルを利用して、文字起こし内容であるコンタクト属性recordingを整形します。

引数と出力

InvokeModelを実行するため、以下の引数を設定しました。
文字起こし内容であるrecordingを整形するためのプロンプトを指定しています。

引数
{
  "ModelId": "arn:aws:bedrock:ap-northeast-1::foundation-model/anthropic.claude-3-5-sonnet-20240620-v1:0",
  "Body": {
    "anthropic_version": "bedrock-2023-05-31",
    "max_tokens": 1000,
    "temperature": 0,
    "messages": [
      {
        "role": "user",
        "content": [
          {
            "type": "text",
            "text": "{% '以下の音声文字起こしテキストから、ご要件、名前、住所の3つの情報を抽出し、以下のフォーマットで整理してください:\n\nご要件:[内容を自然な日本語で記述]\n\nお名前:[名前を記述]\n\nご住所:[住所を記述]\n\nなお、情報が不足している場合は「情報なし」と記載してください。\n余計な説明は不要です。上記フォーマットのみを返してください。\n\nテキスト:\n' & $recording %}"
          }
        ]
      }
    ]
  }
}

cm-hirai-screenshot 2024-12-23 14.47.10

変数recordingを利用する場合、以下のように記述します。&を挟んで使用します。

引数のtextの箇所を抜粋
"text": "`{% '固定のプロンプト内容' & $recording %}`"

実行すると、タスク結果や状態の出力として、以下のように整形された文章が確認できます。

{
  "Body": {
    "id": "msg_bdrk_011VHFJaWYZobCUWnFBzi7h2",
    "type": "message",
    "role": "assistant",
    "model": "claude-3-5-sonnet-20240620",
    "content": [
      {
        "type": "text",
        "text": "ご要件:加湿器が壊れたので連絡した。15時にまた連絡してほしい。\n\nお名前:シライ ユウジ\n\nご住所:情報なし"
      }
    ],
    "stop_reason": "end_turn",
    "stop_sequence": null,
    "usage": {
      "input_tokens": 211,
      "output_tokens": 59
    }
  },
  "ContentType": "application/json"
}

cm-hirai-screenshot 2024-12-23 14.50.51

変数

実行結果であるステートの出力のうち、Bedrockで整形された文章(キー名text)を、次のステートであるSNS Publishでメール通知するために変数として設定します。

ステートの出力
{
  "Body": {
~中略~
    "content": [
      {
        "type": "text",
        "text": "ご要件:加湿器が壊れたので連絡した。15時にまた連絡してほしい。\n\nお名前:シライ ユウジ\n\nご住所:情報なし"
      }
    ],

以下で変数にできます。今回は変数名はbedrock_textにしています。

変数
{
  "bedrock_text": "{% $states.result.Body.content[type=\"text\"].text %}"
}

実行結果を変数にするため、$states.resultを使用します。
JSONataでは、Body.content[type=\"text\"].textと記述することでキー名textを指定できます。

cm-hirai-screenshot 2024-12-23 14.47.18

Task stateのresults

AWS サービスの連携ステート(Task state)を利用する場合、リクエスト結果を$states.resultとして変数にすることはできます。

vars-jsonata
引用元:https://docs.aws.amazon.com/step-functions/latest/dg/transforming-data.html#jsonata-functions-provided-by-sfn

$states.result は、API が成功した場合の結果を指します。

ステートの入力を引数や変数として利用する場合は、"{% $states.input.xxx.xxx %}" と記述します。
また、実行結果であるステートの出力を変数として利用する場合は、"{% $states.result.xxx.xxx %}" と記述します。

設定

設定は以下の通りです。設定タブの[Bedrockモデルパラメータ]には、引数のBodyの設定値がそのまま表示されています。

cm-hirai-screenshot 2024-12-23 14.56.23

SNS Publish

最後に、SNS Publishステートについて解説します。

cm-hirai-screenshot 2024-12-23 14.16.34

引数

SNS Publishステートでは、メール本文にPass state(ParseJSON)ステート、Choiceステート、InvokeModelステートで設定した変数を利用します。

SNS Publishを実行するには、引数としてメール本文(Message)とSNSトピックARNが必要です。

メール送信先であるトピックARNには固定値を使用しています。

引数には、以下の変数を使用します。

  • Pass state(ParseJSON)ステートで設定した変数
    • $InitialContactId:コンタクトID
    • $Time:問い合わせが開始された日時
    • $CallerPhoneNumber:発信元電話番号
  • Choiceステートで設定した変数
    • $recording:コンタクト属性recording(文字起こし内容)
  • InvokeModelステートで設定した変数
    • $bedrock_textrecording(文字起こし内容)をBedrockで整形した文章

メール本文(Message)とSNSトピックARNを以下のように設定しました。

{
  "Message": "{% 'お問い合わせ情報\n\n Contact ID: ' & $InitialContactId & '\n\n・日時:' & $Time & '\n\n・電話番号:' & $CallerPhoneNumber &  '\n\n・お問い合わせ内容(整形済み文章)' & '\n\n' & $bedrock_text & '\n\n・お問い合わせ内容(未整形文章)' & '\n\n' & $recording %}",
  "TopicArn": "arn:aws:sns:ap-northeast-1:xxxxxxxx:cm-hirai"
}

cm-hirai-screenshot 2024-12-23 15.03.07

実際に送信されるメールの内容例は以下の通りです。

お問い合わせ情報

 Contact ID: 78c0a317-4e6f-40e3-b035-4bb8e879b15f

・日時:2024-11-27T01:02:59.076Z

・電話番号:+81xxxxxxxx

・お問い合わせ内容(整形済み文章)

ご要件:先週水曜日に注文した商品が届かず、確認メールも来ていないため、注文状況を確認したい。
お名前:サトウ タロウ
ご住所:東京都港区西新橋1-1-1 日比谷ポートタワー 16階

・お問い合わせ内容(未整形文章)

東京 都 港 区 西新橋 一 の 一 の 一 に 住ん で いる サトウ タロウ と 申し ます 先日 で も 問い合わせ し た ん です が 返事 が なく て 注文 し た 商品 が まだ 届か ない の で 確認 し たく て 電話 し まし た 注文 番号 は わかり ませ ん 住所 は 先程 言っ た 通り な ん です が マンション 名 を 言い 忘れ まし た 日比谷 ポート タワー に 十 六 回 です 実 は 先週 の 水曜 日 に 注文 し た はず な ん です が 確認 メール も 来 なく て 心配 です 普段 は 二 三 日 で 届く と 聞い て い た の で もし か し たら 注文 が 正しく 完了 し て い ない の か な と 思っ て 商品 は 確か 合計 で 一 万 二 千 八 百 円 分 注文 し た ん です が クレジット カード の 引き落とし も 確認 でき て い ませ ん

設定

設定は以下のようになります。設定の [メッセージ] には、引数の Message の設定値が表示されています。

{% 'お問い合わせ情報

 Contact ID: ' & $InitialContactId & '

・日時:' & $Time & '

・電話番号:' & $CallerPhoneNumber &  '

・お問い合わせ内容(整形済み文章)' & '

' & $bedrock_text & '

・お問い合わせ内容(未整形文章)' & '

' & $recording %}

cm-hirai-screenshot 2024-12-23 15.03.23

ステートマシン実行してみた

KDSからステートマシンがトリガーされると、以下のような内容のメールが通知されました。

cm-hirai-screenshot 2024-12-06 16.56.58

今回利用した全体のステートは以下の通りです。

全体のステート(クリックで展開)
{
  "Comment": "Voicemail to Email Notifier State Machine with JSONata",
  "StartAt": "Base64Decode",
  "QueryLanguage": "JSONata",
  "States": {
    "Base64Decode": {
      "Type": "Pass",
      "Next": "ParseJSON",
      "Assign": {
        "decodedData": "{% $base64decode($states.input.data) %}"
      }
    },
    "ParseJSON": {
      "Type": "Pass",
      "Next": "Choice",
      "Assign": {
        "data": "{% $parse($decodedData) %}",
        "InitialContactId": "{% $parse($decodedData).ContactId %}",
        "Time": "{% $parse($decodedData).InitiationTimestamp %}",
        "CallerPhoneNumber": "{% $parse($decodedData).SystemEndpoint.Address %}"
      }
    },
    "Choice": {
      "Type": "Choice",
      "Choices": [
        {
          "Condition": "{% $data.Attributes.recording != null %}",
          "Next": "Bedrock InvokeModel",
          "Assign": {
            "recording": "{% $data.Attributes.recording %}"
          }
        }
      ],
      "Default": "Pass"
    },
    "Bedrock InvokeModel": {
      "Type": "Task",
      "Resource": "arn:aws:states:::bedrock:invokeModel",
      "Arguments": {
        "ModelId": "arn:aws:bedrock:ap-northeast-1::foundation-model/anthropic.claude-3-5-sonnet-20240620-v1:0",
        "Body": {
          "anthropic_version": "bedrock-2023-05-31",
          "max_tokens": 1000,
          "temperature": 0,
          "messages": [
            {
              "role": "user",
              "content": [
                {
                  "type": "text",
                  "text": "{% '以下の音声文字起こしテキストから、ご要件、名前、住所の3つの情報を抽出し、以下のフォーマットで整理してください:\n\nご要件:[内容を自然な日本語で記述]\n\nお名前:[名前を記述]\n\nご住所:[住所を記述]\n\nなお、情報が不足している場合は「情報なし」と記載してください。\n余計な説明は不要です。上記フォーマットのみを返してください。\n\nテキスト:\n' & $recording %}"
                }
              ]
            }
          ]
        }
      },
      "Next": "SNS Publish",
      "Assign": {
        "bedrock_text": "{% $states.result.Body.content[type=\"text\"].text %}"
      }
    },
    "SNS Publish": {
      "Type": "Task",
      "Resource": "arn:aws:states:::sns:publish",
      "Arguments": {
        "Message": "{% 'お問い合わせ情報\n\n Contact ID: ' & $InitialContactId & '\n\n・日時:' & $Time & '\n\n・電話番号:' & $CallerPhoneNumber &  '\n\n・お問い合わせ内容(整形済み文章)' & '\n\n' & $bedrock_text & '\n\n・お問い合わせ内容(未整形文章)' & '\n\n' & $recording %}",
        "TopicArn": "arn:aws:sns:ap-northeast-1:012345678901:cm-hirai"
      },
      "End": true
    },
    "Pass": {
      "Type": "Pass",
      "Comment": "No recording attribute found, ending workflow.",
      "End": true
    }
  }
}

参考

https://docs.aws.amazon.com/step-functions/latest/dg/workflow-variables.html

https://docs.aws.amazon.com/step-functions/latest/dg/transforming-data.html

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.